package com.excilys.service;

import java.util.ArrayList;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.excilys.dao.IAccountDAO;
import com.excilys.dao.ITransactionDAO;
import com.excilys.model.Account;
import com.excilys.model.TransferErrorType;
import com.excilys.model.TransferForm;

/**
 * Class that implements services related to transfers.
 * 
 * @author excilys dev : GF
 * 
 */

@Service
public class TransferFormService {

	Logger logger = LoggerFactory.getLogger(TransferFormService.class);

	@Autowired
	private IAccountDAO accountDAO;
	@Autowired
	private ITransactionDAO transactionDAO;

	/**
	 * Method used by the controller that helps to ensure all the parameters
	 * given by the user are correct
	 * 
	 * @param transferForm
	 * @return
	 */
	public List<TransferErrorType> checkTransfer(TransferForm transferForm) {

		List<TransferErrorType> transferErrorType = new ArrayList<TransferErrorType>();
		Account account = new Account();
		boolean successfulQuery = false;

		try {
			account = accountDAO.getAccountByName(transferForm.getTransactionAccount());
			successfulQuery = true;
		} catch (Exception exception) {
			logger.debug("(!) The TransferFormService has encountered an exception that is likely to be related with an invalid argument for the accountTransaction parameter (no corresponding account found)");
		}

		// If the amount requested is greater than the amount available on the
		// account
		if (successfulQuery == true && transferForm.getTransactionAmount() > (accountDAO.getAccountByName(transferForm.getTransactionAccount())).getAccountAmount()) {
			transferErrorType.add(TransferErrorType.UNAVAILABLE_AMOUNT);
		}
		// If the 2 accounts selected are the same
		else if (successfulQuery == true && transferForm.getTransactionAccount().equals(transferForm.getTransferAccount())) {
			transferErrorType.add(TransferErrorType.SAME_ACCOUNTS);
		}
		// If there is no error
		else {
			transferErrorType.add(TransferErrorType.NO_ERROR);
		}

		return transferErrorType;

	}

	/**
	 * Persists the transfer (the validation method should be called first) and
	 * modifies the accounts amounts. TransferForm takes parameters from VIEW
	 * transfer form
	 * 
	 * @param transferForm
	 */
	@Transactional(readOnly = false)
	public void persistTransfer(TransferForm transferForm) {

		persistOneTransfer(transferForm.getTransactionAccount(), transferForm.getTransferAccount(), transferForm.getTransactionAmount());
	}

	/**
	 * Persists transfer and account amounts
	 * 
	 * @param sourceAccountName
	 * @param targetAccountName
	 * @param transferAmount
	 */
	@Transactional(readOnly = false)
	public void persistOneTransfer(String sourceAccountName, String targetAccountName, double transferAmount) {
		transactionDAO.setTransferTransaction(sourceAccountName, targetAccountName, -transferAmount);

		Account sourceAccount = accountDAO.getAccountByName(sourceAccountName);
		Account targetAccount = accountDAO.getAccountByName(targetAccountName);

		accountDAO.updateAccountBalanceByAccountName(sourceAccountName, (long) (sourceAccount.getAccountAmount() - transferAmount));
		accountDAO.updateAccountBalanceByAccountName(targetAccountName, (long) (targetAccount.getAccountAmount() + transferAmount));
	}

}
